// DSSocketClient.h: interface for the DSSocketClient class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_JSSOCKETCLIENT_H__FB35A9DF_A776_4FE0_8923_21D59A9988D8__INCLUDED_)
#define AFX_JSSOCKETCLIENT_H__FB35A9DF_A776_4FE0_8923_21D59A9988D8__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "../spserver/sphandler.hpp"

#include "remoting\Server.h"
#include "remoting\sockio.h"
#include "remoting/protocol_head.h"


using COM::socket_t;
//using namespace Amf;

class SP_IocpEventArg;
extern struct tagSP_Sid;
typedef tagSP_Sid SP_Sid_t;
class DS_Handle;
#define CS(mutex) critical_section __cs(mutex)
typedef std::multimap<std::wstring, DS_Handle*> DSEventMapType;
class DS_Handle : public SP_Handler
{
	enum StepType { ReadingHead, ReadingDATA };

public:
	DS_Handle()
	{
		m_nStep = ReadingHead;
		m_Head.len = 0;
		m_Head.cmd = 0;
	}

	DS_Handle::~DS_Handle()
	{
		EventClearRegister();
	}

	// return -1 : terminate session, 0 : continue
	virtual int start( SP_Request * request, SP_Response * response );

	// return -1 : terminate session, 0 : continue
	virtual int handle( SP_Request * request, SP_Response * response );

	virtual void error( SP_Response * response );

	virtual void timeout( SP_Response * response );

	virtual void close();

	std::wstring GetClientId () { return L""; }

	// Event
	void EventRegist (LPCWSTR name);
	void EventRemove (std::wstring name);
	void EventUpdateList(Amf::AmfObjectPtr pNameList);
	static void EventDispatch (LPCWSTR name, Amf::AmfObjectPtr obj);
	static void EventGetRegisterList(LPCWSTR name, HT::StdPtrArray &Register);

	// Context
	static DS_Handle* GetCurrentClient ();
	static int GetClientNumber() { return ClientCount;}

protected:
	bool SwitchRequest(DWORD dwLen,DWORD dwStrand,std::vector<unsigned char>& RecvAry);
	Amf::AmfArrayPtr DealwithClientRequest(Amf::AmfObjectPtr ReqObj);

	void OnRequest(unsigned char *data, uint32 len, void* head);
	Amf::AmfObjectPtr m_pClientInfo;

protected:
	SP_Sid_t* GetSeesionSid() { return m_SeesionId; }
	void EventSendTo (LPCWSTR name, Amf::AmfObjectPtr obj);
	static void SetCurrentClient (DS_Handle* pClient);
	static void ClearCurrentClientMap ();

private:
	void SendToClient (Amf::AmfArrayPtr obj, uint16 cmd, uint32 packet_counter);
	void EventClearRegister ();
	COM::mutex m_Mutex;

	StepType m_nStep;
	DATA_HEAD m_Head;
	SP_Response * m_response;

	std::vector<std::wstring> m_EventList;
	static COM::mutex m_EventMutex;
	static COM::mutex m_ContextMutex;
	static DSEventMapType m_EventMap;
	static std::map<int32, DS_Handle*> m_ClientInfoMap;
	static int m_MsgSeq;
	static int ClientCount;

	//yu add 
	SP_Sid_t * m_SeesionId;
};

class DSSocketClient;
class RMT_CLASS_EXPORT DS_Except : public HT::Except
{
public:
	enum LEVEL_TYPE
	{
		LV_DEBUG,
		LV_INFO,
		LV_WARN,
		LV_ERROR,
		LV_FATAL,
	};

	DS_Except (int code, LEVEL_TYPE level = LV_DEBUG, LPCTSTR strWhat = NULL) : HT::Except(code, strWhat), m_nLevel(level)
	{ }
	LEVEL_TYPE GetLevel () { return m_nLevel; }

protected:
	LEVEL_TYPE m_nLevel;	// 0 DEBUG 1 INFO 2 WARN 3 ERROR 4 FATAL
};

#define HT_THROW_INFO(code,what) { std::stringstream str;	str << what;	throw DS_Except(code, DS_Except::LV_INFO, str.str().c_str()); }
#define HT_THROW_WARN(code,what) { std::stringstream str;	str << what;	throw DS_Except(code, DS_Except::LV_WARN, str.str().c_str()); }
#define HT_THROW_ERROR(code,what) { std::stringstream str;	str << what;	throw DS_Except(code, DS_Except::LV_ERROR, str.str().c_str()); }
#define HT_THROW_FATAL(code,what) { std::stringstream str;	str << what;	throw DS_Except(code, DS_Except::LV_FATAL, str.str().c_str()); }

#define HT_CHECK_INFO(condition,err_code,msg)	if(!(condition)) { HT_THROW_INFO(err_code,msg);}
#define HT_CHECK_WARN(condition,err_code,msg)	if(!(condition)) { HT_THROW_WARN(err_code,msg);}
#define HT_CHECK_ERROR(condition,err_code,msg)	if(!(condition)) { HT_THROW_ERROR(err_code,msg);}
#define HT_CHECK_FATAL(condition,err_code,msg)	if(!(condition)) { HT_THROW_FATAL(err_code,msg);}

#define HT_CHECK_RET(condition,ret) if (!(condition)){ return ret;}
#define HT_CHECK_RET_VOID(condition) if (!(condition)){ return;}
#define HT_CHECK(condition) if (!(condition)){HT_THROW_FATAL(HT_BASIC_ERR_UNKNOW,"Assert failed! FileName: " << __FILE__ << ",Line No.:" << __LINE__);}

#define HT_CHECK_ERR_OPERATION(condition,err_code,op,msg)	if(!(condition)) { op;HT_THROW_ERROR(err_code,msg);}

#define HT_CHECK_PARAM(condition,msg) HT_CHECK_ERROR(condition,HT_BASIC_ERR_PARAM_INVALID,msg)

#ifdef  NDEBUG
#define HT_ASSERT(condition)     ((void)0)
#else
#define HT_ASSERT(condition) \
	if(!(condition)) \
	HT_THROW_ERROR(HT_BASIC_ERR_UNKNOW,"assert failed! FileName: " << __FILE__ << ",Line No.: " << __LINE__)
#endif

#endif // !defined(AFX_JSSOCKETCLIENT_H__FB35A9DF_A776_4FE0_8923_21D59A9988D8__INCLUDED_)
